package com.arcaneshift.model.action.game;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import com.arcaneshift.model.abstracts.AbstractCard;
import com.arcaneshift.model.util.ArenaGenerator;
import com.arcaneshift.servlet.util.game.ChangePhaseStory;
import com.arcaneshift.servlet.util.game.DrawCardStory;
import com.arcaneshift.servlet.util.game.Story;

public class BattleEngine implements Serializable {
	private static final long serialVersionUID = 1L;
	private static final int HAND_STARTING_CARDS = 3;
	
	private String id;
	private Calendar time;
	
	@Deprecated
	private List<Story> player1Stories;
	@Deprecated
	private List<Story> player2Stories;
	
	private Deck deck1;
	private Deck deck2;
	
	private Hand hand1;
	private Hand hand2;
	
	private Terran terran;
	private ArenaMap arena;
	private Round round;
	
	public BattleEngine() {
		player1Stories = new ArrayList<Story>();
		player2Stories = new ArrayList<Story>();
		
		round = new Round();
	}
	
	/**
	 * Add a player to this game.
	 */
	public void addPlayer(Player player, Deck deck, Hand hand) {
		BattlePlayer battlePlayer = new BattlePlayer(player, deck, hand);
		round.addBattlePlayer(battlePlayer);
		checkInitGame();
	}
	
	/**
	 * Add a player to this game. Default hand is a new Hand instance
	 */
	public void addPlayer(Player player, Deck deck) {
		BattlePlayer battlePlayer = new BattlePlayer(player, deck, new Hand());
		round.addBattlePlayer(battlePlayer);
		checkInitGame();
	}
	
	public BattlePlayer getPlayerById(Long userId) {
		List<BattlePlayer> battlePlayers = round.getBattlePlayers();
		
		for (BattlePlayer battlePlayer : battlePlayers) {
			if (battlePlayer.getPlayer().getSession().getUserId().equals(userId)) {
				return battlePlayer;
			}
		}
		return null;
	}
	
	/**
	 * Return a list with all the battle players in this game.
	 */
	public List<BattlePlayer> getBattlePlayers() {
		return round.getBattlePlayers();
	}
	
	/**
	 * Return a list with all the players in this game.
	 */
	public List<Player> getPlayers() {
		List<BattlePlayer> battlePlayers = round.getBattlePlayers();
		List<Player> players = new ArrayList<Player>();
		
		for (int i = 0; i < battlePlayers.size(); i++) {
			players.add(battlePlayers.get(i).getPlayer());
		}
		
		return players;
	}
	
	/**
	 * Draw a card from the player's deck and add it to he's hand.
	 */
	public void drawCard(int player) {
		if (player == 1) {
			//player1DrawCard();
			//playerDrawCard(player1, getPlayer1Stories(), getPlayer2Stories());
		} else if (player == 2) {
			//player2DrawCard();
			//playerDrawCard(player2, getPlayer2Stories(), getPlayer1Stories());
		}
	}
	
	public void summonCreature(int player, CreatureCard card, int xPosition, int yPosition) {
		// TODO
	}
	
	public void moveCreature() {
		// TODO
	}
	
	public void attackCreature() {
		// TODO
	}
	
	public void castCreature() {
		// TODO
	}
	
	/**
	 * Load the first 5 cards from the deck to the hand.
	 */
	public void loadStartingHand() {
		for (int i = 0; i < HAND_STARTING_CARDS; i++) {
			//playerDrawCard(player1, getPlayer1Stories(), getPlayer2Stories());
			//playerDrawCard(player2, getPlayer2Stories(), getPlayer1Stories());
		}
	}
	
	/**
	 * Method used for initiating the game's round. It decides who will go first.
	 */
	public void startRounds() {		
		ChangePhaseStory playerStory = new ChangePhaseStory();
		ChangePhaseStory enemyStory = new ChangePhaseStory();
		
		playerStory.setPlayer(round.getCurrentPlayer().getPlayerNumber());
		playerStory.setPhase(round.getCurrentPhase());
		
		enemyStory.setPlayer(round.getCurrentPlayer().getPlayerNumber());
		enemyStory.setPhase(round.getCurrentPhase());
		
		player1Stories.add(playerStory);
		player2Stories.add(enemyStory);
	}
	
	/**
	 * Check if all the players are ready to start the game
	 */
	public boolean playersReady() {
		return round.areBattlePlayersReady();
	}
	
	public void setPlayerReady(int index) {
		round.setBattlePlayerReady(index);
	}
	
	/**
	 * Check if the player with the provided userId is in this game.
	 */
	public boolean containsId(Long userId) {
		return round.containsId(userId);
	}
	
	/**
	 * Check if the game should start by checking the existance of player 1 and 2
	 */
	//TODO Fix this
	private void checkInitGame() {
		if (round.getBattlePlayers().size() > 1) {
			initGame();
		}
	}
	
	private void initGame() {
		terran = ArenaGenerator.generateRandomTerran();
		arena = ArenaGenerator.generateRandomMap();
		
		//ArenaGenerator.loadPlayersNexuses(arena, player1, player2); // What ?
	}
	
	// FRAGMENT METHODS
	
	/**
	 * Draw a card from a player's deck and add it to it's hand.
	 * Create a DrawCardStory for this.
	 * 
	 * @param player - The player that will draw the card
	 * @param playerStories - The player's list of stories
	 * @param enemyStories - The enemy player's list of stories
	 */
	private void playerDrawCard(Player player, List<Story> playerStories, List<Story> enemyStories) {
		AbstractCard card = player.getDeck().drawTopCard();
		player.getHand().addCard(card);
		
		DrawCardStory playerStory = new DrawCardStory();
		DrawCardStory enemyStory = new DrawCardStory();
		
		playerStory.setPlayer(player.getPlayerNumber());
		playerStory.setCard(card);
		
		enemyStory.setPlayer(player.getPlayerNumber());
		
		playerStories.add(playerStory);
		enemyStories.add(enemyStory);
	}
	
	/**
	 * Set this game's player 1 and check if the game can start.
	 */
	@Deprecated
	private void setPlayer1(Player player) {
		//this.player1 = player;
		//this.player1.setPlayerNumber(1);
		checkInitGame();
	}
	
	/**
	 * Set this game's player 2 and check if the game can start.
	 */
	@Deprecated
	private void setPlayer2(Player player) {
		//this.player2 = player;
		//this.player2.setPlayerNumber(2);
		checkInitGame();
	}
	
	// SETTERS AND GETTERS
	
	public void setId(String id) {
		this.id = id;
	}
	
	public String getId() {
		return id;
	}

	public Calendar getTime() {
		return time;
	}

	public void setTime(Calendar time) {
		this.time = time;
	}

	public Terran getTerran() {
		return terran;
	}

	public void setTerran(Terran terran) {
		this.terran = terran;
	}

	public ArenaMap getArena() {
		return arena;
	}

	public void setArena(ArenaMap arena) {
		this.arena = arena;
	}

	public Deck getDeck1() {
		return deck1;
	}

	public void setDeck1(Deck deck1) {
		this.deck1 = deck1;
		//this.player1.setDeck(deck1);
	}

	public Deck getDeck2() {
		return deck2;
	}

	public void setDeck2(Deck deck2) {
		this.deck2 = deck2;
		//this.player2.setDeck(deck2);
	}

	public Hand getHand1() {
		return hand1;
	}

	public void setHand1(Hand hand1) {
		this.hand1 = hand1;
		//this.player1.setHand(hand1);
	}

	public Hand getHand2() {
		return hand2;
	}

	public void setHand2(Hand hand2) {
		this.hand2 = hand2;
		//this.player2.setHand(hand2);
	}
	
	public List<Story> getPlayer1Stories() {
		return player1Stories;
	}
	
	public List<Story> getPlayer2Stories() {
		return player2Stories;
	}
}
